import { Meta, Status, Props, Story } from "../../../../.storybook/components";
import * as Stories from "./AutocompleteInput.stories";

<Meta of={Stories} />

# AutocompleteInput

<Status variant="experimental" />

An input field that allows users to filter and select one or many options from a provided set of options.

<Story of={Stories.Base} />
<Props />

## When to use

Use the AutocompleteInput component when you want to help users find and select from a large set of options. Common use cases:

- Location picker: Address or city field
- Product catalog: choosing from a long list of products

For short lists, consider using the [Select](Forms/Select/Docs) component instead.

While the AutocompleteInput component is accessible, it can be complex to interact with, especially for keyboard and screen reader users. Use it only when necessary and aim to keep the interaction simple and to respect the component usage recommendations as much as possible.

## How to use

- Use the `onSearch` prop to update the list of options as the user types. You can optionally set the `minQueryLength` prop to delay this behavior until a minimum number of characters has been typed.
- Use the `onChange` prop to handle the selection of an option and set the input's `value` prop to the selected option. After the selection, make sure to reset the value of the `options` prop.
- Use the `onClear` prop to handle the clearing of the input field, and reset the input's `value` prop to reflect this change.
- The component can receive a flat list or a list of grouped options via the `options` prop. To ensure a consistent and user-friendly experience, keep the visual format uniform. For example, make sure all options include (or not) an image or a description. Keep labels and descriptions short and easy to scan.
- To enable multiple selections, set the `multiple` prop to "true". In this mode, the `value` prop must be an array of `AutocompleteInputOption` objects. The `onChange` callback will still receive a single `AutocompleteInputOption`—the option that was just selected or removed. The `updateMultipleSelectionValue` utility function can be used to compute the new value of the field.
- To support the selection of the user's input as the field's value, enable the `allowNewItems` prop. This will display the user's input as an available option in the list box.

<Story of={Stories.AllowNewItems} />

- For a mobile-optimized experience, use the "immersive" `variant` to open the AutocompleteInput in a modal dialog on narrow viewports.

## Customisation

- The "no results" screen can be customised using the `noResultsMessage` prop.
- The "loading" message can be customised using the `loadingLabel` prop.
- The "load more" button label can be customised using the `loadMoreLabel` prop.
- The options can be customised by adding avatar images or icons and a description.
- Use the `action` prop to add a contextual action at the bottom of the list box, such as a button to create a new item.

<Story of={Stories.WithAction} />

## Performance

### Debouncing

The component's `onSearch` callback is debounced by default to avoid excessive calls while the user types. The debounce delay is set to 300 ms.

### Paginated results

For better performance and scalability when loading dynamic, paginated results, use the `loadMore` prop to fetch additional options. When this prop is provided, a "Load more" button appears at the bottom of the list box. You can customize the button label with `loadMoreLabel`. Use the `isLoadingMore` prop to indicate that more options are being fetched, and `aria-setsize` to convey the total number of options available to assistive technologies. Learn more about `aria-setsize` in the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-setsize).

<Story of={Stories.LoadMore} />

### Fetching options

To ensure you always show the most relevant options, consider using an [Abort Controller](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to cancel previous fetch requests. This prevents showing outdated options and improves the user experience.

```tsx
import { useState, useCallback, useRef } from "react";
import { AutocompleteInput } from "@sumup-oss/circuit-ui";

const MyComponent = () => {
  const [options, setOptions] = useState([]);
  const abortControllerRef = useRef<AbortController | null>(null);

  const fetchOptions = useCallback(async (query: string) => {
    // Abort previous request if it exists
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
    // Create a new AbortController for the new request
    const controller = new AbortController();
    abortControllerRef.current = controller;

    try {
      const results = await getOptions(query, controller.signal);
      setOptions(results);
    } catch (error) {
      if (error.name !== "AbortError") {
        // Handle non-abort errors (e.g., server issues)
      }
    }
  }, []);

  return (
    <AutocompleteInput
      label="Customer"
      placeholder="Search for a customer"
      options={options}
      onSearch={fetchOptions}
    />
  );
};

async function getOptions(query: string, signal: AbortSignal) {
  const response = await fetch(`https://my-search-api.com?query=${query}`, {
    signal,
  });
  if (!response.ok) {
    throw new Error("Network response was not ok");
  }
  return response.json();
}
```

## Accessibility

The AutocompleteInput component is designed to be accessible, adopting ARIA's [Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/). It includes:

### Keyboard navigation

- Arrow down key: Opens the list box
- Escape key: Closes the list box
- Arrow Up/Down keys: navigate through options
- Enter key: selects an option
- Backspace key: deletes a selected option in multi-selection mode.

### Screen reader support

The component announces the number of options available and the selected option, if any.

### Focus management

The component manages focus appropriately. The focus remains on the input field when the list box is open, and navigated options are announced properly as the user navigates through them.
